package com.zhss.dfs.upgrade;

import com.zhss.dfs.server.DataNodeConfig;
import com.zhss.dfs.server.NioFileServer;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @description:
 * @Author liu Weidong
 * @Email:
 * @Date: 2024/6/2 10:26
 * @Version 1.0
 */
public class NetworkRequest {

    public static final Integer READ_TYPE = 1;
    public static final Integer SEND_TYPE = 2;

    private SocketChannel socketChannel;

    private SelectionKey key;

    private String client;

    private String processorId;

    private CacheRequest cacheRequest = new CacheRequest();

    /**
     * 缓存请求类型
     */
    private ByteBuffer cacheRequestTypeBuffer;

    /**
     * 缓存文件名长度信息
     */
    private ByteBuffer cacheFileNameLengthBuffer;

    /**
     * 缓存文件名
     */
    private ByteBuffer cacheFileNameBuffer;

    /**
     * 缓存文件长度
     */
    private ByteBuffer cacheFileLengthBuffer;

    /**
     * 缓存文件内容
     */
    private ByteBuffer cacheFileBuffer;

    public SocketChannel getSocketChannel() {
        return socketChannel;
    }

    public void setSocketChannel(SocketChannel socketChannel) {
        this.socketChannel = socketChannel;
    }

    public SelectionKey getKey() {
        return key;
    }

    public void setKey(SelectionKey key) {
        this.key = key;
    }

    public String getClient() {
        return client;
    }

    public void setClient(String client) {
        this.client = client;
    }

    public boolean hasCompletedRead(){
        return cacheRequest.hasCompletedRead;
    }

    public String getProcessorId() {
        return processorId;
    }

    public void setProcessorId(String processorId) {
        this.processorId = processorId;
    }

    public Integer getType(){
        return cacheRequest.requestType;
    }

    public FileName getFileName(){
        return cacheRequest.fileName;
    }

    public Long getFileLength(){
        return cacheRequest.fileLength;
    }
    public ByteBuffer getFile(){
        return cacheRequest.file;
    }

    public void read() {
        try {
            Integer requestType = null;
            if (cacheRequest.requestType != null) {
                requestType = cacheRequest.requestType;
            } else {
                requestType = getRequestType();
            }
            if (requestType == null) {
                return;
            }
            if (requestType.equals(SEND_TYPE)) {
                handleSendFileRequest(socketChannel, key);
            } else if (requestType.equals(READ_TYPE)) {
                handleReadFileRequest(socketChannel, key);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void handleReadFileRequest(SocketChannel socketChannel, SelectionKey key) throws Exception {
        FileName fileName = getFileName(socketChannel);
        if (fileName == null) {
            return;
        }
        cacheRequest.fileName = fileName;
        cacheRequest.hasCompletedRead = true;
    }

    private void handleSendFileRequest(SocketChannel socketChannel, SelectionKey key) throws Exception {
        // 获取文件名信息
        FileName fileName = getFileName(socketChannel);
        if (fileName == null) {
            return;
        }
        // 获取文件长度
        Long fileLength = getFileLength(socketChannel);
        if (fileLength == null) {
            return;
        }
        //读取文件
        ByteBuffer fileBuffer = cacheFileBuffer == null ? ByteBuffer.allocate(fileLength.intValue()) : cacheFileBuffer;
        int read = socketChannel.read(fileBuffer);
        System.out.println("本次读取字节数：" + read);
        if (!fileBuffer.hasRemaining()) {
            fileBuffer.rewind();
            cacheRequest.file = fileBuffer;
            cacheRequest.hasCompletedRead = true;
        } else {
            cacheFileBuffer = fileBuffer;
            key.interestOps(SelectionKey.OP_READ);
            System.out.println("本次文件上传存在拆包问题");
        }
    }

    private Long getFileLength(SocketChannel socketChannel) throws Exception{
        Long fileLength = null;
        ByteBuffer fileLengthBuffer = null;
        if (cacheRequest.fileLength != null) {
            return cacheRequest.fileLength;
        }
        fileLengthBuffer = cacheFileLengthBuffer != null ? cacheFileLengthBuffer : ByteBuffer.allocate(8);
        socketChannel.read(fileLengthBuffer);
        if (!fileLengthBuffer.hasRemaining()) {
            fileLengthBuffer.rewind();
            fileLength = fileLengthBuffer.getLong();
            cacheRequest.fileLength = fileLength;
            System.out.println("文件程度为： " + fileLength);
        } else {
            cacheFileLengthBuffer = fileLengthBuffer;
            return null;
        }
        return fileLength;
    }

    private FileName getFileName(SocketChannel socketChannel) throws Exception {
        FileName fileName = null;
        if (cacheRequest.fileName != null) {
            fileName = cacheRequest.fileName;
        } else {
            String relativeFileName = getRelativeFileName(socketChannel);
            if (relativeFileName == null) {
                return null;
            }
            String absolutePath = DataNodeConfig.FILE_DATA + relativeFileName;
            fileName = new FileName(absolutePath,relativeFileName);
            cacheRequest.fileName = fileName;
        }
        return fileName;
    }

    private String getRelativeFileName(SocketChannel socketChannel) throws Exception {
        Integer fileNameLength = null;
        ByteBuffer buffer = null;
        // 读取文件名长度
        if (cacheRequest.fileNameLength != null) {
            fileNameLength = cacheRequest.fileNameLength;
        } else {
            buffer = cacheFileNameLengthBuffer != null ? cacheFileNameLengthBuffer : ByteBuffer.allocate(4);
            socketChannel.read(buffer);
            if (!buffer.hasRemaining()) {
                buffer.rewind();
                fileNameLength = buffer.getInt();
                cacheRequest.fileNameLength = fileNameLength;
                System.out.println("文件名长度为：" + fileNameLength);
            } else {
                cacheFileNameLengthBuffer = buffer;
                return null;
            }
        }
        // 读取文件名
        String fileName = null;
        ByteBuffer fileNameBuffer = cacheFileNameBuffer != null ? cacheFileNameBuffer : ByteBuffer.allocate(fileNameLength);
        socketChannel.read(fileNameBuffer);
        if (!fileNameBuffer.hasRemaining()) {
            fileNameBuffer.rewind();
            fileName = new String(fileNameBuffer.array());
        } else {
            cacheFileNameBuffer = fileNameBuffer;
        }
        return fileName;
    }

    private Integer getRequestType() throws Exception {
        ByteBuffer byteBuffer = null;
        if (cacheRequestTypeBuffer != null) {
            byteBuffer = cacheRequestTypeBuffer;
        } else {
            byteBuffer = ByteBuffer.allocate(4);
        }
        socketChannel.read(byteBuffer);
        if (!byteBuffer.hasRemaining()) {
            byteBuffer.rewind();
            int requestType = byteBuffer.getInt();
            cacheRequest.requestType = requestType;
            return requestType;
        } else {
            // 没有读完拆包了
            cacheRequestTypeBuffer = byteBuffer;
        }
        return null;
    }


    class CacheRequest {
        FileName fileName;
        Integer requestType;
        Long fileLength;
        Integer fileNameLength;
        ByteBuffer file;
        Boolean hasCompletedRead = false;
    }
}
